<template>
    <div v-loading="loading" :element-loading-delay="tableData.length > 0 ? 120 : 0" class="console-page">
        <el-row class="toolbar">
            <el-col :span="24" style="text-align:right">
                <el-button :icon="getIcon('refresh')" class="button-auto-resize" circle @click="getData"/>
                <el-button :icon="getIcon('plus')" class="button-auto-resize" @click="newData" circle/>
            </el-col>
        </el-row>
        <el-table :data="tableData" border header-cell-class-name="el-table-header-cell" cell-class-name="el-table-cell"
                  class="e-page table-without-pagination" highlight-current-row>
            <el-table-column type="index" label="序号" :width="fontAutoResize.size_6.value"/>
            <el-table-column prop="AppType" label="应用类型" min-width="250"/>
            <el-table-column prop="CidrBlock" label="来源" :width="fontAutoResize.size_12.value"/>
            <el-table-column prop="Protocol" label="协议" sortable :width="fontAutoResize.size_8.value"/>
            <el-table-column prop="Port" label="端口" :width="fontAutoResize.size_8.value"/>
            <el-table-column prop="Action" label="策略" sortable :width="fontAutoResize.size_8.value">
                <template #default="scope">
                    <el-tag :type="scope.row.Action === 'DROP' ? 'danger' : 'success'"
                            class="forbid-select button-auto-resize" disable-transitions>
                        {{ scope.row.Action === 'DROP' ? '拒绝' : '允许' }}
                    </el-tag>
                </template>
            </el-table-column>
            <el-table-column prop="FirewallRuleDescription" label="备注" min-width="350"/>
            <el-table-column label="操作" fixed="right" :width="operationWidth" className="operation-column">
                <template #default="scope">
                    <el-button type="danger" :icon="getIcon('SwitchButton')" circle @click="closeRule(scope)"
                               class="button-auto-resize"/>
                    <el-button type="danger" :icon="getIcon('Delete')" circle @click="deleteRule(scope)"
                               class="button-auto-resize"/>
                    <el-button type="primary" :icon="getIcon('EditPen')" circle @click="editRule(scope.row)"
                               class="button-auto-resize"/>
                </template>
            </el-table-column>
        </el-table>
        <el-drawer :title="title" v-model="dialogVisible" size="500" class="forbid-select firewall" @closed="close"
                   :show-close="false" :close-on-click-modal="!submitting" :close-on-press-escape="!submitting"
                   append-to-body>
            <div>
                <div class="rule-item">
                    <span class="rule-label" checklabel>来源</span>
                    <span class="rule-value">
                        <el-input v-model="curInfo.CidrBlock" placeholder="请输入IP地址或CIDR段"
                                  class="input-auto-resize"
                                  check="ip"/>
                    </span>
                </div>
                <div class="rule-item">
                    <span class="rule-label">协议</span>
                    <span class="rule-value">
                        <el-select v-model="curInfo.Protocol" placeholder="选择协议类型" style="width:100%"
                                   class="input-auto-resize" popper-class="normal-poper">
                            <el-option v-for="(item, index) in ['TCP', 'UDP', 'ICMP']" :key="index" :label="item"
                                       :value="item">
                            </el-option>
                        </el-select>
                    </span>
                </div>
                <div class="rule-item">
                    <span class="rule-label" checklabel>端口</span>
                    <span class="rule-value">
                        <el-input v-model="curInfo.Port" placeholder="如53,80,8080或80-90" class="input-auto-resize"
                                  check="port"/>
                    </span>
                </div>
                <div class="rule-item">
                    <span class="rule-label">策略</span>
                    <span class="rule-value">
                        <el-switch v-model="curInfo.Action" active-text="允许" inactive-text="拒绝"
                                   active-value="ACCEPT"
                                   inactive-value="DROP" class=" fit-auto-resize cursor-pointer" inline-prompt/>
                        <span :style="`color: ${curInfo.Action === 'DROP' ? 'red' : 'green'};`" class="status-desc">
                            {{ curInfo.Action === 'ACCEPT' ? '端口策略立即生效' : '添加端口策略，但策略不会生效' }}
                        </span>
                    </span>
                </div>
                <div class="rule-item">
                    <span class="rule-label">备注</span>
                    <span class="rule-value">
                        <el-input v-model="curInfo.FirewallRuleDescription" placeholder="规则备注信息,最多50个字符"
                                  :maxlength="50"
                                  class="input-auto-resize" type="textarea" resize="none" :rows="10"/>
                    </span>
                </div>
            </div>
            <template #footer>
                <div class="dialog-footer">
                    <el-button type="primary" @click="submit" class="fit-auto-resize">提交</el-button>
                    <el-button @click="dialogVisible = false" class="fit-auto-resize">取消</el-button>
                </div>
            </template>
        </el-drawer>
    </div>
</template>

<script setup>
import {useSetTableOperationWidth, useModalSize, useRequest, useElLoading, useElMessage, useDataCheck} from "@usehook"
import {getIcon} from "@/utils/tools"
import {ElMessageBox} from 'element-plus'
import {fontAutoResize} from "@/utils/setting"
import router from "@/router"

const operationWidth = useSetTableOperationWidth(3)
let tableData = $ref([])
let loading = $ref(false)
let dialogVisible = $ref(false)
let curInfo = $ref({CidrBlock: '0.0.0.0/0', Protocol: 'TCP', Action: 'ACCEPT'})
let backCurInfo = $ref({})
let submitting = $ref(false)
const instance = router.currentRoute.value.query

let title = computed(() => {
    return curInfo.edit ? '编辑防火墙规则' : '新增防火墙规则'
})

const blockChecker = (value) => {
    let check = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])(?:\/(3[0-2]|[1-2][0-9]|[1-9]?[0-9]))?$/.test(value);
    if (check && value.includes('/')) {
        check = parseInt(value.split('/')[1]) < 33
    }
    return check ? "" : "请输入有效的IP地址或CIDR段"
}

const portChecker = (value) => {
    let message = value?.trim() ? '' : "端口号不能为空"
    if (value.toLowerCase() === 'all') {
        curInfo.Port = 'ALL'
        value = 'ALL'
    }
    if (value !== 'ALL') {
        const numberPart = value.replace(/[,-]/g, '')
        let checkNumberPart = /^\d+$/.test(numberPart)
        if (checkNumberPart) {
            if (value.includes(',') && value.includes('-')) {
                message = '请输入正确格式,如80,81,82或80-82'
            } else if (value.startsWith(',') || value.startsWith('-') || value.endsWith(',') || value.endsWith('-')) {
                message = '请输入正确格式,如80,81,82或80-82'
            } else if (value.includes('-')) {
                if (numberPart.length !== value.length - 1) {
                    message = '请输入正确格式,如80,81,82或80-82'
                } else {
                    const sp = value.split('-')
                    const v1 = parseInt(sp[0])
                    const v2 = parseInt(sp[1])
                    if (v1 > v2 || v1 > 65535 || v1 < 0 || v2 > 65535 || v2 < 0) {
                        message = '端口号取值范围0-65535,且前项小于后项'
                    }
                }
            } else if (value.includes(',')) {
                const sp = value.split(',')
                for (let i of sp) {
                    if (parseInt(i) < 0 || parseInt(i) > 65535) {
                        message = '端口号取值范围0-65535'
                    }
                }
            } else {
                message = parseInt(value) >= 0 && parseInt(value) <= 65535 ? '' : '端口号取值范围0-65535'
            }
        } else {
            message = '请输入正确格式,如80,81,82或80-82'
        }
    }
    return message
}

const getData = (showLoading = true) => {
    if (showLoading) loading = true
    useRequest("/tencentCloud/describeFirewallRules", instance).then(resp => {
        if (resp && resp.status) {
            tableData = resp.data.FirewallRuleSet || []
        }
    }).catch((error) => {
        if (error.message) useElMessage.error(error.message)
    }).finally(_ => {
        if (showLoading) loading = false
    })
}

const deleteRule = (scope) => {
    const row = scope.row
    const index = scope.$index + 1
    useModalSize()
    ElMessageBox.confirm(`<div>确认删除规则<span style="color: #0088cc;width: 30px;display: inline-block;text-align: center;">${index}</span>?</div>
                                 <div style="display: flex;gap: 40px">
                                     <div>类型：${row.AppType}</div>
                                     <div>来源：${row.CidrBlock}</div>
                                     <div>端口：${row.Port}</div>
                                     <div>协议：${row.Protocol}</div>
                                 </div>`, '提示', {
        dangerouslyUseHTMLString: true,
        confirmButtonText: ' ',
        cancelButtonText: ' ',
        type: 'warning',
        customClass: "c-dialog forbid-select",
        closeOnClickModal: false,
        cancelButtonClass: "iconfont icon-close button-auto-resize",
        confirmButtonClass: 'iconfont icon-check button-auto-resize',
        roundButton: true,
        showClose: false,
    }).then(() => {
        loading = true
        useRequest.post("/tencentCloud/deleteFirewallRule", {
            removeRule: Object.fromEntries(
                Object.entries(row).filter(([_, value]) => value !== '')
            ), ...instance
        }).then(resp => {
            if (resp && resp.status) {
                getData(false)
            } else if (resp.message) {
                useElMessage.error(resp.message)
            }
        }).finally(_ => {
            loading = false
        })
    }).catch(_ => {
    }).finally(() => {
        useModalSize(false)
    })
}

const editRule = (row) => {
    backCurInfo = {...row}
    curInfo = {...row, edit: true}
    dialogVisible = true
    useModalSize()
}

const closeRule = (scope) => {
    const row = scope.row
    const index = scope.$index + 1
    useModalSize()
    ElMessageBox.confirm(`<div>确认${row.Action === 'DROP' ? '开启' : '暂停'}规则<span style="color: #0088cc;width: 30px;display: inline-block;text-align: center;">${index}</span>?</div>
                                 <div style="display: flex;gap: 40px">
                                     <div>类型：${row.AppType}</div>
                                     <div>来源：${row.CidrBlock}</div>
                                     <div>端口：${row.Port}</div>
                                     <div>协议：${row.Protocol}</div>
                                 </div>`, '提示', {
        dangerouslyUseHTMLString: true,
        confirmButtonText: ' ',
        cancelButtonText: ' ',
        type: 'warning',
        customClass: "c-dialog forbid-select",
        closeOnClickModal: false,
        cancelButtonClass: "iconfont icon-close button-auto-resize",
        confirmButtonClass: 'iconfont icon-check button-auto-resize',
        roundButton: true,
        showClose: false,
    }).then(() => {
        loading = true
        backCurInfo = {...row}
        curInfo = {...row, edit: true}
        curInfo.Action = curInfo.Action === "ACCEPT" ? "DROP" : "ACCEPT"
        submit()
    }).catch(_ => {
    }).finally(() => {
        loading = false
        useModalSize(false)
    })
}

const newData = () => {
    curInfo.edit = false
    dialogVisible = true
    useModalSize()
}

const {check} = useDataCheck({"port": portChecker, "ip": blockChecker})

const close = () => {
    curInfo = {CidrBlock: '0.0.0.0/0', Protocol: 'TCP', Action: 'ACCEPT'}
    backCurInfo = {}
    useModalSize(false)
}

const submit = () => {
    check().then(() => {
        const loading = useElLoading({
            target: ".el-dialog",
            lock: true,
            background: 'rgba(255, 255, 255, 0.5)',
            text: "正在提交防火墙策略"
        })
        submitting = true
        useRequest.post(curInfo.edit ? '/tencentCloud/modifyFirewallRule' : '/tencentCloud/createFirewallRule', {
            ...instance,
            newRule: curInfo,
            backRule: backCurInfo
        }).then(resp => {
            if (resp.status) {
                dialogVisible = false
                getData(false)
            } else if (resp.message) useElMessage.error(resp.message)
        }).finally(_ => {
            submitting = false
            loading.close()
            close()
        })
    })
}

onMounted(() => {
    getData()
})
</script>

<style>
.firewall .el-dialog__body {
    padding: 10px;
}

.toolbar .instance-label {
    height: 100%;
    display: inline-flex;
    font-size: var(--font-size);
    line-height: var(--font-size);
    justify-content: center;
    align-items: center;
    padding: 0 10px;
    margin-left: 5px;
    background: #cdcdcd;
    border-radius: 3px;
}

.toolbar .instance-label.active {
    background: #85d1ff;
}

.firewall .rule-label {
    width: 70px;
    display: inline-block;
    text-align: center;
}

.firewall .rule-value {
    width: calc(100% - 80px);
    display: inline-block;
    position: relative;
}

.firewall .rule-item + .rule-item {
    padding-top: 20px;
}

.firewall .el-drawer__footer {
    padding: 20px 50px 20px 20px;
}

.firewall .error {
    top: 20%;
    left: unset;
    right: 5px;
    pointer-events: none;
}

.firewall .el-drawer__body {
    overflow: hidden;
}

.firewall .status-desc {
    font-size: calc(var(--font-size) - 2px);
    padding-left: 10px;
}
</style>